package com.example.demo.configuration;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.demo.utils.JwtUtil;
import com.example.demo.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.MimeHeaders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @description:
 * @author: cj
 * @create: 17-12-22 17:53:39
 */
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Value("${jwt.token-header}")
    private String jwtTokenHeader;
    @Resource
    JwtUtil jwtUtil;

    /**
     * 在Controller请求执行之前，
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.info( "路径" + request.getServletPath() );
        // 返回值表示是否向下执行，如果返回false，那么中止执行链。通常发送HTTP错误或编写自定义响应给请求端
        //获取token access-token
        String token = StringUtil.isEmpty( request.getHeader( this.jwtTokenHeader ) )?
                StringUtil.isEmpty( request.getHeader( "authorization" ) )?null:request.getHeader( "authorization" )
                :request.getHeader( this.jwtTokenHeader );
        Cookie[] cookies = request.getCookies();
        if (token == null) {
            if (!ArrayUtil.isEmpty( cookies )) {
                for (Cookie cookie : cookies) {
                    if (this.jwtTokenHeader.equals( cookie.getName() )) {
                        token = cookie.getValue();
                        break;
                    }
                }
            }
            throw new RuntimeException( "token过期" );
        }
        if (token != null && !"".equals( token ) && !"undefined".equals( token )) {
            DecodedJWT verify = jwtUtil.verify( token );
            if (verify == null) {
                throw new RuntimeException( "token过期" );
            } else {
                System.out.println( verify );
                Claim user = verify.getClaim( "user" );
                JSONObject jsonObject = JSON.parseObject( user.asString() );
                String user1 = verify.getClaim( "user" ).toString();
                System.out.println( user1 );
                Map<String, String> map = new HashMap<>();
                String id = jsonObject.get( "_id" ).toString();
                map.put( "_id", id );
                //添加用户信息到请求头
//                modifyHeader( request, map );

                return true;
            }
        } else {
            throw new RuntimeException( "token过期" );
        }

    }

    /**
     * Controller处理之后，渲染完成之前
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 整个请求完成执行完之后
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    /**
     * 修改request请求头信息，只适用于Tomcat
     *
     * @param servletRequest request
     * @param map            修改HeaderKey  修改HeaderValue map
     */
    private void modifyHeader(HttpServletRequest servletRequest, Map<String, String> map) {
        try {

            // RequestFacade是HttpServletRequest的实现类
            // getDeclaredField 仅能获取类本身的属性成员（包括私有、共有、保护）
            // 获取org.apache.catalina.connector.RequestFacade类中request字段
            log.info( "HttpServletRequest implement class is {}", servletRequest.getClass().getName() );
            //获取org.apache.catalina.connector.RequestFacade类中request字段
            Field requestField = servletRequest.getClass().getDeclaredField( "request" );
            //设置字段跳过安全检查
            requestField.setAccessible( true );
            //获取javax.servlet.http.HttpServletRequest实现类中request字段对象:org.apache.catalina.connector.Request
            Object requestObject = requestField.get( servletRequest );

            log.info( "RequestFacade class filed request implement class is {}.", requestObject.getClass().getName() );
            //获取org.apache.catalina.connector.Request类中coyoteRequest字段
            Field coyoteRequestField = requestObject.getClass().getDeclaredField( "coyoteRequest" );
            //设置字段跳过安全检查
            coyoteRequestField.setAccessible( true );
            //获取org.apache.catalina.connector.Request实现类中coyoteRequest字段对象：org.apache.catalina.connector.Request.coyoteRequest
            Object coyoteRequestObject = coyoteRequestField.get( requestObject );

            log.info( "org.apache.coyote.Request class filed coyoteRequest implement class is {}", coyoteRequestObject.getClass().getName() );
            //获取org.apache.catalina.connector.Request.coyoteRequest类中headers字段
            Field headersField = coyoteRequestObject.getClass().getDeclaredField( "headers" );
            //设置字段跳过安全检查
            headersField.setAccessible( true );
            //获取org.apache.catalina.connector.Request.coyoteRequest实现类中headers字段对象实现：org.apache.tomcat.util.http.MimeHeaders
            Object headersObject = headersField.get( coyoteRequestObject );
            //确定字段类型为：org.apache.tomcat.util.http.MimeHeaders
            if (headersObject instanceof MimeHeaders) {
                //使用MimeHeaders类方法设置Header值
                MimeHeaders headers = (MimeHeaders) headersObject;
                Iterator<String> iterator = map.keySet().iterator();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    headers.removeHeader( key );
                    //addValue只添加，setValue会遍历查找，如果不存在此Header再添加
                    //headers.addValue(headerKey).setString(headerValue);
                    headers.setValue( key ).setString( map.get( key ) );
                    log.info( "update request Headers success:{}", servletRequest.getHeader( key ) );
                }
            }
        } catch (Exception e) {
            log.error( "添加header出错:", e );
        }
    }


}
